//! system管理各用户的信息
use std::sync::Arc;

use ane_system::dao::{UpdateUserDo, User, UserListFilter, UserVo};
use axum::{
    extract::{Path, Query},
    http::StatusCode,
    response::IntoResponse,
    routing::{get, post},
    Extension, Router,
};
use common::page::{PageInfo, PageParams};
use gen_table::model::Order;
use serde::Deserialize;
use validator::Validate;

use crate::{
    auth_manager::AuthManager,
    error::{AppError, AppResult},
    extract::{Json, ValJson},
    AppState,
};

pub fn get_route<S>() -> Router<S>
where
    S: Sync + Send + Clone + 'static,
{
    Router::<S>::new()
        .route("/", get(list).post(create))
        .route("/update_password", post(update_password))
        .route("/:id", get(fetch_one).put(update).delete(delete))
}

pub async fn fetch_one(
    Extension(state): Extension<Arc<AppState>>,
    Path(id): Path<i32>,
) -> AppResult<impl IntoResponse> {
    User::get_detail_by_id(state.db(), id)
        .await
        .map(Json)
        .map_err(Into::into)
}

#[derive(Deserialize)]
pub struct ListQuery {
    order: Option<String>,
    dept_id: Option<i32>,
    #[serde(flatten)]
    filter: UserListFilter,
}

pub async fn list(
    Extension(state): Extension<Arc<AppState>>,
    Query(query): Query<ListQuery>,
    Query(page_params): Query<PageParams>,
) -> AppResult<impl IntoResponse> {
    let order = query
        .order
        .map(|f| Order::parse_to_map(&f))
        .map(|f| f.get("created_at").map(Order::is_asc))
        .flatten();
    User::list(
        state.db(),
        page_params.zero_page(),
        page_params.page_size,
        query.dept_id,
        order,
        Some(query.filter),
    )
    .await
    .map(|(total, datas)| PageInfo::new(datas, &page_params, total))
    .map(Json)
    .map_err(Into::into)
}

pub async fn create(
    Extension(state): Extension<Arc<AppState>>,
    ValJson(data): ValJson<ane_system::dao::NewUserDo>,
) -> AppResult<impl IntoResponse> {
    if User::check_name(state.db(), &data.username).await? {
        let info = format!("user '{}' exist", data.username);
        return Ok((StatusCode::CONFLICT, info).into_response());
    }
    User::create(state.db(), data)
        .await
        .map(Json)
        .map(IntoResponse::into_response)
        .map_err(Into::into)
}

pub async fn update(
    Extension(state): Extension<Arc<AppState>>,
    Extension(ane_system_manager): Extension<AuthManager>,
    Path(id): Path<i32>,
    ValJson(mut data): ValJson<UpdateUserDo>,
) -> AppResult<impl IntoResponse> {
    let user: UserVo = User::get_by_id(state.db(), id, None)
        .await?
        .ok_or(AppError::NotFount)?;
    // 禁止修改 admin 用户的status
    if user.username == "admin" {
        data.status = None;
        data.dept_id = None;
    }
    let res = User::update(state.db(), id, data)
        .await
        .map(Json)
        .map_err(Into::into);
    // 更新就清除缓存
    ane_system_manager.clean_users_cache(vec![id]).await;
    res
}

pub async fn delete(
    Extension(state): Extension<Arc<AppState>>,
    Extension(ane_system_manager): Extension<AuthManager>,
    Path(id): Path<i32>,
) -> AppResult<impl IntoResponse> {
    let user: UserVo = User::get_by_id(state.db(), id, None)
        .await?
        .ok_or(AppError::NotFount)?;
    // 禁止删除 admin 用户
    if user.username == "admin" {
        Err(AppError::Forbidden)?
    }
    let res = User::delete(state.db(), &id)
        .await
        .map_err(Into::into)
        .map(|_| "Ok");
    // 更新就清除缓存
    ane_system_manager.clean_users_cache(vec![id]).await;
    res
}

#[derive(Deserialize, Validate)]
pub struct ChangePasswordDo {
    id: i32,
    #[validate(length(min = 3, max = 32), non_control_character)]
    new_pwd: String,
}

/// 管理员直接修改用户的密码
pub async fn update_password(
    Extension(state): Extension<Arc<AppState>>,
    ValJson(data): ValJson<ChangePasswordDo>,
) -> AppResult<impl IntoResponse> {
    User::change_password(state.db(), data.id, &data.new_pwd).await?;
    Ok("Ok".to_owned())
}
